//
//  NSData+DataConvert.m
//  OutdoorAssistantApplication
//
//  Created by 罗亮富 on 15/9/25.
//  Copyright © 2015年 Lolaage. All rights reserved.
//

#import "NSData+DataConvert.h"


@implementation NSMutableData (LolaageIMPackage)


-(void)addByteData:(U8)byteVal
{
    [self appendBytes:&byteVal length:1];
}

-(void)addShortData:(S16)shortVal
{
    [self appendBytes:&shortVal length:2];
}

-(void)addShortData:(S16)shortVal toEdian:(EDIAN_T)edian
{
    changeValEdian(&shortVal, sizeof(shortVal), edian);
    [self addShortData:shortVal];
}

-(void)addIntData:(U32)intVal
{
    [self appendBytes:&intVal length:4];
}

-(void)addIntData:(U32)intVal toEdian:(EDIAN_T)edian
{
    changeValEdian(&intVal, sizeof(intVal), edian);
    [self addIntData:intVal];
}

-(void)addLongData:(S64)longVal
{
    [self appendBytes:&longVal length:8];
}

-(void)addLongData:(S64)longVal toEdian:(EDIAN_T)edian
{
    changeValEdian(&longVal, sizeof(longVal), edian);
    [self addLongData:longVal];
}


-(void)addFloatData:(FLOAT)floatVal
{
    [self appendBytes:&floatVal length:4];
}

-(void)addFloatData:(FLOAT)floatVal toEdian:(EDIAN_T)edian
{
    changeValEdian(&floatVal, sizeof(floatVal), edian);
    [self addFloatData:floatVal];
}

-(void)addDoubleData:(DOUBLE)doubleVal
{
    [self appendBytes:&doubleVal length:8];
}

-(void)addDoubleData:(DOUBLE)doubleVal toEdian:(EDIAN_T)edian
{
    changeValEdian(&doubleVal, sizeof(doubleVal), edian);
    [self addDoubleData:doubleVal];
}

-(void)addCoordinateData:(CLLocationCoordinate2D)coordinate
{
    [self addDoubleData:coordinate.longitude];
    [self addDoubleData:coordinate.latitude];
    

}

//添加long 的number 数组
-(void)addLongNumberArray:(NSArray <NSNumber *> *)array
{
    //如果数组为空或数组中没有对象，则只向Data中添加一个0值。
    if(!array || array.count == 0) {
        [self addShortData:0];
        return;
    }
    
    //向Data中添加数组的长度。
    [self addShortData:array.count];
    //把数组里面每一个对象的Data都添加到data中。
    for (NSNumber * object in array)
    {
        if ([object isKindOfClass:[NSNumber class]]) {
            NSMutableData *numberdata = [NSMutableData data];
            long number = [object longValue];
            [numberdata addLongData:number];
            
            [self appendData:numberdata];
        }else{
#if DEBUG
            NSLog(@"appending Array is not NSNumber");
#endif
        }

    }
}

-(NSDate *)extractDate
{
    NSTimeInterval sec = (double)[self extractLonglong];
    return [NSDate dateWithTimeIntervalSince1970:sec/1000.0];
}



-(U8)extractByte
{
    if(self.length<sizeof(U8))
        return 0;
    
    U8 p = *((U8 *)[self bytes]);
    [self replaceBytesInRange:NSMakeRange(0, 1) withBytes:NULL length:0];
    return p;
}

-(S16)extractShort
{
    if(self.length<sizeof(S16))
        return 0;
    
    S16 p = *((S16 *)[self bytes]);
    [self replaceBytesInRange:NSMakeRange(0, 2) withBytes:NULL length:0];
    return p;
}

-(S16)extractShortFromEdian:(EDIAN_T)edian
{
    S16 v = [self extractShort];
    changeValEdian(&v, sizeof(v), edian);
    return v;
}

-(S32)extractInt
{
    if(self.length<sizeof(S32))
        return 0;
    
    S32 p = *((S32 *)[self bytes]);
    [self replaceBytesInRange:NSMakeRange(0, 4) withBytes:NULL length:0];
    return p;
}

-(S32)extractIntFromEdian:(EDIAN_T)edian
{
    S32 v = [self extractInt];
    changeValEdian(&v, sizeof(v), edian);
    return v;
}

-(S64)extractLonglong
{
    if(self.length<sizeof(S64))
        return 0;
    
    S64 p = *((S64 *)[self bytes]);
    [self replaceBytesInRange:NSMakeRange(0, 8) withBytes:NULL length:0];
    return p;
}

-(S64)extractLonglongFromEdian:(EDIAN_T)edian
{
    S64 v = [self extractLonglong];
    changeValEdian(&v, sizeof(v), edian);
    return v;
}

-(FLOAT)extractFloat
{
    if(self.length<sizeof(FLOAT))
        return 0.00;
    FLOAT p = *((FLOAT *)[self bytes]);
    [self replaceBytesInRange:NSMakeRange(0, sizeof(FLOAT)) withBytes:NULL length:0];
    return p;
}

-(FLOAT)extractFloatFromEdian:(EDIAN_T)edian
{
    FLOAT v = [self extractFloat];
    changeValEdian(&v, sizeof(v), edian);
    return v;
}

-(DOUBLE)extractDouble
{
    if(self.length<sizeof(DOUBLE))
        return 0.00;
    
    DOUBLE p = *((DOUBLE *)[self bytes]);
    [self replaceBytesInRange:NSMakeRange(0, sizeof(DOUBLE)) withBytes:NULL length:0];
    return p;
}

-(DOUBLE)extractDoubleFromEdian:(EDIAN_T)edian
{
    DOUBLE v = [self extractDouble];
    changeValEdian(&v, sizeof(v), edian);
    return v;
}

-(CLLocationCoordinate2D)extractCoordinate
{
    CLLocationCoordinate2D coordinate;

    coordinate.longitude = [self extractDouble];
    coordinate.latitude = [self extractDouble];
//    coordinate.longitude = [self extractFloat];
//    coordinate.latitude = [self extractFloat];
    return coordinate;
}

-(NSData *)extractDataOfLength:(NSUInteger)len
{
    if(self.length<len)
        return nil;
    
    NSData *data = [self subdataWithRange:NSMakeRange(0, len)];
    [self replaceBytesInRange:NSMakeRange(0, len) withBytes:NULL length:0];
    return data;
}


//-(NSArray *)extractArrayOfClass:(Class)className
//{
//    if(self.length < 2)
//        return nil;
//    NSUInteger count = [self extractShort];
//
//    if(count == 0)
//        return nil;
//
//    NSMutableArray *mArray = [NSMutableArray arrayWithCapacity:count];
//    for (int i = 0; i < count; i ++) {
//        id obj;
//        if (className == [NSString class]) {
//            obj = [self extractString];
//        }else{
//            obj = [[className alloc]initByExtractingDataFromData:self];
//        }
//        [mArray addObject:obj];
//    }
//    return mArray;
//}


@end


void changeValEdian(void *val, int size, EDIAN_T edian)
{
    if(edian != judgeEndian() && size>=2)//只有当其平台大小端与目标不一致时才需转换
    {
        char tmp[8];
        char *p = (char *)val;
        memcpy(tmp, val, size);
        for(int i=size-1;i>=0;i--)
        {
            *p = tmp[i];
            p++;
        }
    }
}

//判断当前平台的大小端模式 1:大端 2:小端
EDIAN_T judgeEndian(void)
{
    static EDIAN_T endian = 0;
    if(endian != 0)
        return endian;
    
    short a = 0x1122;//十六进制，一个数值占4位
    char b =  *(char *)&a;  //通过将short(2字节)强制类型转换成char单字节，b指向a的起始字节（低字节）
    if( b == 0x11)//低字节存的是数据的高字节数据
    {
        endian = H_ED; //根据协议 1代表大端
    }
    else
    {
        endian = L_ED; //根据协议 用2代表小端
    }
    return endian;
}

